package com.webchat.ugc.service.redpacket;

import com.webchat.common.constants.RedPacketConstants;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.exception.BusinessException;
import com.webchat.domain.vo.response.RedPacketBaseVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;


/**
 * 方案三：预先计算好每分红包金额，走队列一次获取
 */
@Service
public class OpenRedPacketWithQueueService extends AbstractOpenRedPacketService {


    @Override
    public int openRedPacket(RedPacketBaseVO redPacket, String userId) {

        Long redPacketId = redPacket.getId();
        String queueKey = this.redPacketAmountQueueCacheKey(redPacket.getId());
        // 走队列获取预先计算好的红包金额，因为redis的单线程命令执行特性，所以这里是并发安全的
        String amount = redisService.lrightPop(queueKey);
        if (StringUtils.isBlank(amount)) {
            // 红包被拆分完
            super.updateRedPacketStatus(redPacketId, RedPacketConstants.RedPacketStatus.END);
            throw new BusinessException("来晚了，红包已拆完");
        }
        int amountVal = Integer.valueOf(amount);
        // 添加用户到红包拆分人员名单缓存
        addUser2OpenRedPacketUsersCache(redPacketId, userId);
        return amountVal;
    }

    public List<Integer> preGeneratedRedPackets(Long redPacketId, int totalMoneyFen, int gradCount) {
        List<Integer> redPackets = new ArrayList<>();
        // 递归生成红包金额
        this.doRecursivePreGenerated(totalMoneyFen, gradCount, redPackets);
        // 加入队列
        String queueKey = this.redPacketAmountQueueCacheKey(redPacketId);
        redisService.lleftPushAll(queueKey, redPackets);
        return redPackets;
    }

    private String redPacketAmountQueueCacheKey(Long redPacketId) {

        return RedisKeyEnum.QUEUE_RED_PACKET_AMOUNT.getKey(String.valueOf(redPacketId));
    }


    private void doRecursivePreGenerated(int balanceMoneyFen, int gradCountBalance, List<Integer> redPackets) {

        if (gradCountBalance == 1) {
            // 跳出条件
            redPackets.add(balanceMoneyFen);
            return;
        }

        // 二倍均值
        BigDecimal avgAmount = new BigDecimal(balanceMoneyFen).divide(new BigDecimal(gradCountBalance), 0, BigDecimal.ROUND_HALF_UP);
        BigDecimal avgAmount2 = avgAmount.multiply(new BigDecimal(2));
        int maxVal = avgAmount2.intValue();
        // 在[minVal, maxVal]之间随机一个红包金额：openAmount
        int openAmount = ThreadLocalRandom.current().nextInt(RedPacketConstants.MIN_AMOUNT, maxVal + 1);
        redPackets.add(openAmount);

        doRecursivePreGenerated(balanceMoneyFen - openAmount, gradCountBalance - 1, redPackets);
    }

    public static void main(String[] args) {
        List<Integer> redPackets = new ArrayList<>();
        int gradCount = 10;
        // 设置红包金额（分）
        int totalMoneyFen = new BigDecimal("100").multiply(new BigDecimal(100)).intValue();
        // 递归生成红包金额
//        doRecursivePreGenerated(totalMoneyFen, gradCount, redPackets);
        System.out.printf("预先计算好红包：" + redPackets);
    }
}
